﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Library
{
	abstract class GameScreen
	{
		#region Fields
		public enum ScreenState { Active, Hidden, TransitionOn, TransitionOff }

		protected ContentManager content;

		//The time it takes to transition the screen on
		private float _transitionOnTime = 0.0f;
		public float TransitionOnTime { get { return _transitionOnTime; } }

		//The time it takes to transition the screen off
		private float _transitionOffTime = 0.0f;
		public float TransitionOffTime { get { return _transitionOffTime; } }

		private float _transitionTimer = 0.0f;

		//For fading sprites
		private float _spritesFadeSmoothness = 1;
		private bool _spritesAreFading = false;

		//State of the screen
		public ScreenState state;

		//ScreenManager the screen belongs to
		public ScreenManager screenManager;

		//ContentManager used for loading sprites
		private ContentManager _contentManager;

		//SpriteBatch used for drawing sprites
		private SpriteBatch _spriteBatch;

		//Is the screen a pop up?
		private bool _isPopUp;
		public bool IsPopUp { get { return _isPopUp; } }

		private bool graphicsInstantiated = false;

		private Effect shader;

		//List of sprites not added because the graphics have not been instantiated yet
		private List<Sprite> spritesNotAdded = new List<Sprite>();

		//List of lightsources
		private List<LightSource> lightSources = new List<LightSource>();

		//used for moving the camera and zooming
		protected Camera2D camera = new Camera2D();

		//Is the screen only covering temporary? Used if you do not want to remove the covered screen
		private bool _isTempCovering;
		public bool IsTempCovering { get { return _isTempCovering; } }

		//Sprites attached to the gamescreen
		private List<Sprite> _spritesToDraw = new List<Sprite>();
		private bool isExiting;

		#endregion

		#region Constructors
		public GameScreen(bool isPopUp, bool isTempCovering)
		{
			_isPopUp = isPopUp;
			_isTempCovering = isTempCovering;
		}
		public GameScreen(bool isPopUp, bool isTempCovering, float transitionOnTime, float transitionOffTime)
		{
			_isPopUp = isPopUp;
			_isTempCovering = isTempCovering;
			_transitionOnTime = transitionOnTime;
			_transitionOffTime = transitionOffTime;
		}
		public GameScreen(bool isPopUp, bool isTempCovering, float transitionOnTime, float transitionOffTime, int spritesFadeSmoothness)
		{
			_isPopUp = isPopUp;
			_isTempCovering = isTempCovering;
			_transitionOnTime = transitionOnTime;
			_transitionOffTime = transitionOffTime;
			_spritesFadeSmoothness = spritesFadeSmoothness;
		}
		#endregion
		
		#region Methods
		public virtual void HandleInput(InputState inputState) { }
		public virtual void LoadContent() { }
		public void Draw(GameTime gameTime) 
		{
			if (graphicsInstantiated)
			{
				_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null,shader, camera.GetTransformation(screenManager.GraphicsDevice));
				DrawSprites(gameTime);
				CustomDraw(gameTime);
				_spriteBatch.End();
			}
			else
			{
				InstantiateGraphics();
			}
		}
		private void DrawSprites(GameTime gameTime)
		{
			Rectangle screenRectangle = Camera2D.GetScreenRectangle();
			foreach (Sprite sprite in _spritesToDraw)
			{
				#region Checks if the sprites are currently fading
				if (!_spritesAreFading)
				{
					if (state == ScreenState.TransitionOff)
					{
						sprite.FadeOut(_transitionOffTime, _spritesFadeSmoothness);
						_spritesAreFading = true;
					}
					else if (state == ScreenState.TransitionOn)
					{
						sprite.FadeIn(_transitionOnTime, _spritesFadeSmoothness);
						_spritesAreFading = true;
					}
				}
				#endregion

				if(screenRectangle.Contains(sprite.CollisionRectangle) || screenRectangle.Intersects(sprite.CollisionRectangle))
				{
					DrawLighting(sprite);
					sprite.Draw(gameTime);
					
				}
			}
		}
		private void DrawLighting(Sprite sprite)
		{
			float brightness = 1.0f;
			foreach(LightSource lightSource in lightSources)
			{
				brightness = (float)(lightSource.CalculateBrightness(sprite));
				if (brightness >= 1.0f)
				{
					brightness = 1.0f;
					break;
				}
				shader.Parameters["distanceFromObject"].SetValue(brightness);
				shader.Parameters["colorOfLight"].SetValue(sprite.color.ToVector4());
			}

		}
		public virtual void CustomDraw(GameTime gameTime){}
		public virtual void Update(GameTime gameTime) { }
		public void InstantiateGraphics()
		{
			if (!graphicsInstantiated && screenManager.isInitialized)
			{
				_spriteBatch = screenManager.spriteBatch;
				_contentManager = new ContentManager(screenManager.Game.Services, "Content\\");
				graphicsInstantiated = true;
				shader = _contentManager.Load<Effect>("Shaders/PixelShader");
				foreach (Sprite sprite in spritesNotAdded)
				{
					sprite.LoadContent(_contentManager, _spriteBatch);
					_spritesToDraw.Add(sprite);
				}
				spritesNotAdded.Clear();
			}
		}
		public void Add(Sprite sprite)
		{
			if (graphicsInstantiated)
			{
				sprite.LoadContent(_contentManager, _spriteBatch);
				_spritesToDraw.Add(sprite);
			}
			else
			{
				spritesNotAdded.Add(sprite);
			}
		}
		public void AddLight(LightSource lightSource)
		{
			lightSources.Add(lightSource);
		}
		public void Remove(Sprite sprite)
		{
			_spritesToDraw.Remove(sprite);
		}
		public void FadeOutThenIn(float fadeTime, float fadeSmoothness)
		{
			foreach (Sprite sprite in _spritesToDraw)
			{
				sprite.FadeOut(fadeTime, fadeSmoothness);
			}
			foreach (Sprite sprite in _spritesToDraw)
			{
				sprite.FadeIn(fadeTime, fadeSmoothness);
			}
		}
		public virtual void UpdateState(GameTime gameTime,bool covered)
		{
			if (covered)
			{
				if (StillTransitioning(gameTime, _transitionOffTime))
				{
					state = ScreenState.TransitionOff;
				}
				else
				{
					state = ScreenState.Hidden;
				}
			}
			else
			{
				if (StillTransitioning(gameTime, _transitionOnTime) == false)
				{
					state = ScreenState.Active;
				}
				else
				{
					state = ScreenState.TransitionOn;
				}
			}
		}
		private bool StillTransitioning(GameTime gameTime, float transitionTime)
		{
			_transitionTimer += gameTime.ElapsedGameTime.Milliseconds;
			if (_transitionTimer >= transitionTime)
			{
				_transitionTimer = 0.0f;
				return false;
			}
			else
			{
				return true;
			}
		}
		#endregion
	}
}
